#include "HYDetect.h"
#include "HYFaceDetectManager.h"
#include "napi/native_api.h"
#include <cstddef>
#include <cstdint>

int8_t rgbaToBgr(void *buffer, size_t length) {
    unsigned char *src = (unsigned char *)buffer;
    if (src == NULL || length < 4) {
        return -1;
    }

    size_t pixelCount = length / 4;
    unsigned char *dst = src; // 输出缓冲区与输入重叠

    for (size_t i = 0; i < pixelCount; i++) {
        // 从RGBA源读取
        unsigned char r = src[0];
        unsigned char g = src[1];
        unsigned char b = src[2];
        // 忽略alpha通道 src[3]

        // 写入BGR目标
        dst[0] = b;
        dst[1] = g;
        dst[2] = r;

        src += 4; // 移动到下一个RGBA像素
        dst += 3; // 移动到下一个BGR位置
    }
    return 0;
}

static napi_value Detect(napi_env env, napi_callback_info info) {
    size_t argc = 5;
    napi_value args[5] = {nullptr};

    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    if (argc < 5) {
        napi_throw_error(env, nullptr, "数据参数缺失");
        return nullptr;
    }

    int64_t addrValue = 0;
    bool flag = false;
    napi_status status = napi_get_value_bigint_int64(env, args[0], &addrValue, &flag);
    if (status != napi_ok || addrValue == 0) {
        napi_throw_error(env, nullptr, "参数1转换失败");
        return nullptr;
    }

    // 检查参数是否是 ArrayBuffer 类型
    bool isArrayBuffer = false;
    status = napi_is_arraybuffer(env, args[1], &isArrayBuffer);
    if (status != napi_ok || !isArrayBuffer) {
        napi_throw_error(env, nullptr, "参数不是有效的 ArrayBuffer");
        return nullptr;
    }
    // 获取传入的图片数据 (Buffer)
    void *bufferData;
    size_t bufferLength;
    status = napi_get_arraybuffer_info(env, args[1], &bufferData, &bufferLength);
    if (status != napi_ok) {
        napi_throw_error(env, nullptr, "无法获取 ArrayBuffer 信息");
        return nullptr;
    }


    int64_t imgwidth = 0;
    status = napi_get_value_int64(env, args[2], &imgwidth);
    if (status != napi_ok || imgwidth == 0) {
        napi_throw_error(env, nullptr, "参数imgwidth转换失败");
        return nullptr;
    }

    int64_t imgheight = 0;
    status = napi_get_value_int64(env, args[3], &imgheight);
    if (status != napi_ok || imgheight == 0) {
        napi_throw_error(env, nullptr, "参数imgheight转换失败");
        return nullptr;
    }
    if (imgheight * imgwidth * 4 != bufferLength) {
        napi_throw_error(env, nullptr, "图片字节数组与图片宽高不符");
        return nullptr;
    }

    int32_t returnFaceImage = 0;
    status = napi_get_value_int32(env, args[4], &returnFaceImage);
    if (status != napi_ok) {
        napi_throw_error(env, nullptr, "参数returnFaceImage转换失败");
        return nullptr;
    }

    HYFaceDetectManager *detectMamager = (HYFaceDetectManager *)addrValue;
    int8_t convertResult = rgbaToBgr(bufferData, bufferLength);
    if (convertResult != 0) {
        napi_throw_error(env, nullptr, "rgbaToBgr error");
        return nullptr;
    }
    int faceNumber = 0;
    float facequality = 0;
    float facex = 0;
    float facey = 0;
    float facewidth = 0;
    float faceheight = 0;
    float faceroll = 0;
    float faceyaw = 0;
    float facepitch = 0;
    int faceshakeLeft = 0;
    int faceshakeRight = 0;
    int facejawOpen = 0;
    int faceheadRaise = 0;
    int faceblink = 0;
    int outimgwidth = 0;
    int outimgheight = 0;

    uint8_t *outimage = nullptr;
    int8_t detectResult = detectMamager->detect(
        (uint8_t *)bufferData, imgwidth, imgheight, &faceNumber, &facequality, &facex, &facey, &facewidth, &faceheight,
    &faceroll, &faceyaw, &facepitch, &faceshakeLeft, &faceshakeRight, &facejawOpen, &faceheadRaise,
        &faceblink, returnFaceImage, &outimage, &outimgwidth, &outimgheight);

    napi_value object = nullptr;
    napi_create_object(env, &object);

    if (returnFaceImage == 1) {
        napi_value returnImageArrayBufferV;
        size_t le = outimgwidth * outimgheight * 4;
        void *data = nullptr;
        status = napi_create_arraybuffer(env, le, &data, &returnImageArrayBufferV);
        if (status != napi_ok) {
            if (outimage != nullptr) {
                free(outimage);
                outimage = nullptr;
            }
            napi_throw_error(env, nullptr, "napi_create_arraybuffer失败");
            return nullptr;
        }

        uint8_t *ui8Buffer = reinterpret_cast<uint8_t *>(data);
        for (int i = 0; i < le; i++) {
            ui8Buffer[i] = (uint8_t)(outimage[i]);
        }
        if (outimage != nullptr) {
            free(outimage);
            outimage = nullptr;
        }


        napi_value returnImageWidthP = nullptr;
        // 设置属性名为"returnImageWidth"
        napi_create_string_utf8(env, "returnImageWidth", NAPI_AUTO_LENGTH, &returnImageWidthP);
        napi_value returnImageWidthV = nullptr;
        napi_create_uint32(env, outimgwidth, &returnImageWidthV);
        napi_set_property(env, object, returnImageWidthP, returnImageWidthV);

        napi_value returnImageHeightP = nullptr;
        // 设置属性名为"returnImageHeight"
        napi_create_string_utf8(env, "returnImageHeight", NAPI_AUTO_LENGTH, &returnImageHeightP);
        napi_value returnImageHeightV = nullptr;
        napi_create_uint32(env, outimgheight, &returnImageHeightV);
        napi_set_property(env, object, returnImageHeightP, returnImageHeightV);

        napi_value returnImageArrayBufferP = nullptr;
        // 设置属性名为"returnImageArrayBuffer"
        napi_create_string_utf8(env, "returnImageArrayBuffer", NAPI_AUTO_LENGTH, &returnImageArrayBufferP);
        napi_set_property(env, object, returnImageArrayBufferP, returnImageArrayBufferV);
    }

    // status
    napi_value statusP = nullptr;
    napi_create_string_utf8(env, "status", NAPI_AUTO_LENGTH, &statusP);
    napi_value statusV = nullptr;
    napi_create_uint32(env, detectResult, &statusV);
    napi_set_property(env, object, statusP, statusV);

    // faceNumber
    napi_value faceNumberP = nullptr;
    napi_create_string_utf8(env, "faceNumber", NAPI_AUTO_LENGTH, &faceNumberP);
    napi_value faceNumberV = nullptr;
    napi_create_uint32(env, faceNumber, &faceNumberV);
    napi_set_property(env, object, faceNumberP, faceNumberV);

    // faceShakeLeft
    napi_value faceShakeLeftP = nullptr;
    napi_create_string_utf8(env, "faceShakeLeft", NAPI_AUTO_LENGTH, &faceShakeLeftP);
    napi_value faceShakeLeftV = nullptr;
    napi_create_uint32(env, faceshakeLeft, &faceShakeLeftV);
    napi_set_property(env, object, faceShakeLeftP, faceShakeLeftV);

    // faceShakeRight
    napi_value faceShakeRightP = nullptr;
    napi_create_string_utf8(env, "faceShakeRight", NAPI_AUTO_LENGTH, &faceShakeRightP);
    napi_value faceShakeRightV = nullptr;
    napi_create_uint32(env, faceshakeRight, &faceShakeRightV);
    napi_set_property(env, object, faceShakeRightP, faceShakeRightV);

    // faceJawOpen
    napi_value faceJawOpenP = nullptr;
    napi_create_string_utf8(env, "faceJawOpen", NAPI_AUTO_LENGTH, &faceJawOpenP);
    napi_value faceJawOpenV = nullptr;
    napi_create_uint32(env, facejawOpen, &faceJawOpenV);
    napi_set_property(env, object, faceJawOpenP, faceJawOpenV);

    // faceHeadRaise
    napi_value faceHeadRaiseP = nullptr;
    napi_create_string_utf8(env, "faceHeadRaise", NAPI_AUTO_LENGTH, &faceHeadRaiseP);
    napi_value faceHeadRaiseV = nullptr;
    napi_create_uint32(env, faceheadRaise, &faceHeadRaiseV);
    napi_set_property(env, object, faceHeadRaiseP, faceHeadRaiseV);

    // faceBlink
    napi_value faceBlinkP = nullptr;
    napi_create_string_utf8(env, "faceBlink", NAPI_AUTO_LENGTH, &faceBlinkP);
    napi_value faceBlinkV = nullptr;
    napi_create_uint32(env, faceblink, &faceBlinkV);
    napi_set_property(env, object, faceBlinkP, faceBlinkV);

    // faceQuality
    napi_value faceQualityP = nullptr;
    napi_create_string_utf8(env, "faceQuality", NAPI_AUTO_LENGTH, &faceQualityP);
    napi_value faceQualityV = nullptr;
    napi_create_double(env, facequality, &faceQualityV);
    napi_set_property(env, object, faceQualityP, faceQualityV);

    // facex
    napi_value faceXP = nullptr;
    napi_create_string_utf8(env, "faceX", NAPI_AUTO_LENGTH, &faceXP);
    napi_value faceXV = nullptr;
    napi_create_double(env, facex, &faceXV);
    napi_set_property(env, object, faceXP, faceXV);

    // facey
    napi_value faceYP = nullptr;
    napi_create_string_utf8(env, "faceY", NAPI_AUTO_LENGTH, &faceYP);
    napi_value faceYV = nullptr;
    napi_create_double(env, facey, &faceYV);
    napi_set_property(env, object, faceYP, faceYV);

    // facewidth
    napi_value faceWidthP = nullptr;
    napi_create_string_utf8(env, "faceWidth", NAPI_AUTO_LENGTH, &faceWidthP);
    napi_value faceWidthV = nullptr;
    napi_create_double(env, facewidth, &faceWidthV);
    napi_set_property(env, object, faceWidthP, faceWidthV);

    // faceheight
    napi_value faceHeightP = nullptr;
    napi_create_string_utf8(env, "faceHeight", NAPI_AUTO_LENGTH, &faceHeightP);
    napi_value faceHeightV = nullptr;
    napi_create_double(env, faceheight, &faceHeightV);
    napi_set_property(env, object, faceHeightP, faceHeightV);

    // faceroll
    napi_value faceRollP = nullptr;
    napi_create_string_utf8(env, "faceRoll", NAPI_AUTO_LENGTH, &faceRollP);
    napi_value faceRollV = nullptr;
    napi_create_double(env, faceroll, &faceRollV);
    napi_set_property(env, object, faceRollP, faceRollV);

    // faceyaw
    napi_value faceYawP = nullptr;
    napi_create_string_utf8(env, "faceYaw", NAPI_AUTO_LENGTH, &faceYawP);
    napi_value faceYawV = nullptr;
    napi_create_double(env, faceyaw, &faceYawV);
    napi_set_property(env, object, faceYawP, faceYawV);

    // facepitch
    napi_value facePitchP = nullptr;
    napi_create_string_utf8(env, "facePitch", NAPI_AUTO_LENGTH, &facePitchP);
    napi_value facePitchV = nullptr;
    napi_create_double(env, facepitch, &facePitchV);
    napi_set_property(env, object, facePitchP, facePitchV);
    return object;
}

static napi_value ReleaseDetect(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value args[1] = {nullptr};

    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    if (argc < 1) {
        napi_throw_error(env, nullptr, "数据参数缺失");
        return nullptr;
    }

    int64_t addrValue = 0;
    bool flag = false;
    napi_status status = napi_get_value_bigint_int64(env, args[0], &addrValue, &flag);
    if (status != napi_ok || addrValue == 0) {
        napi_throw_error(env, nullptr, "参数1转换失败");
        return nullptr;
    }
    HYFaceDetectManager *faceDetectMamager = (HYFaceDetectManager *)addrValue;
    faceDetectMamager->releaseHYFaceDetectManager();
    faceDetectMamager = nullptr;
    return nullptr;
}


EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {
    napi_property_descriptor desc[] = {
        {"detect", nullptr, Detect, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"releaseDetect", nullptr, ReleaseDetect, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"arkTSConstructor", nullptr, HYDetect::ArkTSConstructor, nullptr, nullptr, nullptr, napi_default, nullptr},
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

static napi_module demoModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "hfacedetect",
    .nm_priv = ((void *)0),
    .reserved = {0},
};

extern "C" __attribute__((constructor)) void RegisterHFaceDetectModule(void) { napi_module_register(&demoModule); }
